﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace BFlatCompile.Nodes
{
	public class TryBlock : Executable
	{
		public Executable[] TryCode { get; private set; }
		public Executable[] CatchCode { get; private set; }
		public Executable[] FinallyCode { get; private set; }
		public Variable ExceptionName { get; private set; }

		private TryBlock(Executable[] tryCode, Executable[] catchCode, Executable[] finallyCode, Token exceptionName)
		{
			this.TryCode = tryCode;
			this.CatchCode = catchCode;
			this.FinallyCode = finallyCode;
			this.ExceptionName = exceptionName != null ? new Variable(exceptionName.Value, exceptionName) : null;
		}

		public static TryBlock Parse(Tokens tokens)
		{
			tokens.PopExpected("try");
			Executable[] tryCode = CodeBlock.Parse(tokens, true);
			Token exceptionName = null;
			Executable[] catchCode = null;
			Executable[] finallyCode = null;

			if (tokens.PopIfPresent("catch"))
			{
				if (tokens.PopIfPresent("("))
				{
					tokens.PopIdentifier();
					exceptionName = tokens.PreviousToken();
					tokens.PopIfPresent(")");
				}

				catchCode = CodeBlock.Parse(tokens, true);
			}

			if (tokens.PopIfPresent("finally"))
			{
				finallyCode = CodeBlock.Parse(tokens, true);
			}

			return new TryBlock(tryCode, catchCode, finallyCode, exceptionName);
		}

		public override void ResolveCode(Class c, Dictionary<object, object> parents)
		{
			foreach (Executable[] code in new Executable[][] { this.TryCode, this.CatchCode, this.FinallyCode })
			{
				if (code != null)
				{
					foreach (Executable line in code)
					{
						line.ResolveCode(c, parents);
					}
				}
			}
		}

		public override void ResolveClassToThis(Class c)
		{
			foreach (ICodeContainer code in new Consolidator()
				.Add(this.TryCode)
				.Add(this.CatchCode)
				.Add(this.FinallyCode)
				.List())
			{
				code.ResolveClassToThis(c);
			}
		}
	}
}
